#include <Ape/Collections/Queue.h>
#include <Ape/Exception.h>

#include <Ape/MT/Mutex.h>

namespace Ape {
	namespace Collections {
		using Ape::MT::MutexLock;
		
		struct QueueJoint {
			void* Element;
			QueueJoint* Next;
			QueueJoint* Prev;
			
			static QueueJoint* create (void* element = NULL) {
				QueueJoint* j = new QueueJoint;
				j->Element = element;
				j->Next = NULL;
				j->Prev = NULL;
				
				return j;
			}
			
			void append (QueueJoint* nextOne) {
				this->Next = nextOne;
				if (nextOne) {
					nextOne->Prev = this;
				}
			}
		};
		
		
		QueueImpl::QueueImpl()
				: m_Head (NULL),
				m_Tail (NULL),
				m_Count (0)
		{
			InitObjectMutex();
		}
		
		QueueImpl::~QueueImpl() {}
		
		void QueueImpl::purge() {
			while (get_Count() ) {
				FreePtr (_Dequeue (true) );
			}
		}
		
		
		void QueueImpl::_Enqueue (void* pElement) {
			MutexLock lock (GetObjectMutex() );
			QueueJoint* j = QueueJoint::create (pElement);
			if (!m_Tail) {
				m_Tail = j;
				m_Head = j;
			}
			else {
				m_Tail->append (j);
				m_Tail = j;
			}
			m_Count++;
		}
		
		void* QueueImpl::_Dequeue (bool noThrow) {
			MutexLock lock (GetObjectMutex() );
			QueueJoint* j = m_Head;
			if (j) {
				QueueJoint* j = m_Head;
				void* pElement = j->Element;
				
				m_Head = j->Next;
				delete j;
				
				if (!m_Head) {
					m_Tail = NULL;
				}
				m_Count--;
				return pElement;
			}
			else {
				if (!noThrow)
					throw Exception (L"The queue is empty");
				else
					return NULL;
			}
		}
		
		size_t QueueImpl::get_Count() const {
			return m_Count;
		}
		
		void QueueImpl::_Dump (bool verbose) const {
			Object::_Dump (verbose);
			
			DUMP_NON_V_TYPE;
			size_t iCount = get_Count();
			
			printf ("\t\tCount:\t%i\n", iCount);
			
			if (verbose) {
				printf ("\t\tDumping elements:\n");
				
				for (QueueJoint* j = m_Head; j != NULL; j = j->Next) {
					void* p = j->Element;
					Object* o = reinterpret_cast<Object*> (p);
					printf ("\t\t\ttype: '%s' (addr: [%p])\n", o->getVTypeName(), (void*) o);
				}
			}
		}
	}
}
